<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>卷材计算器 · 单文件</title>
  <style>
    :root{--bg:#f7f9fc;--card:#fff;--text:#0f172a;--muted:#6b7280;--primary:#2563eb;--ring:#93c5fd;--border:#e5e7eb;--danger:#ef4444}
    *{box-sizing:border-box}
    html,body{height:100%}
    body{margin:0;background:var(--bg);color:var(--text);font:16px/1.5 system-ui,-apple-system,Segoe UI,Roboto,Ubuntu,Cantarell,Noto Sans,Helvetica,Arial,"Apple Color Emoji","Segoe UI Emoji"}
    .container{max-width:1100px;margin:0 auto;padding:24px}
    h1{display:flex;gap:10px;align-items:center;margin:0 0 18px;font-size:22px}
    .grid{display:grid;gap:16px}
    @media(min-width:980px){.grid{grid-template-columns:2fr 1fr}}
    .card{background:var(--card);border:1px solid var(--border);border-radius:12px}
    .card-h{padding:14px 16px;border-bottom:1px solid var(--border);font-weight:600}
    .card-b{padding:16px}
    .row{display:grid;gap:12px}
    @media(min-width:680px){.row{grid-template-columns:1fr 1fr}}
    .field{display:flex;flex-direction:column;gap:6px}
    label{font-size:13px;color:var(--muted)}
    .input-wrap{display:flex;gap:8px}
    input[type=number]{flex:1;appearance:textfield;padding:10px 12px;border:1px solid var(--border);border-radius:10px;font:inherit;outline:0;background:#fff}
    input[type=number]:focus{border-color:var(--ring);box-shadow:0 0 0 3px color-mix(in oklab,var(--ring) 35%,transparent)}
    input::placeholder{color:#9ca3af}
    .btn{cursor:pointer;border:1px solid var(--border);background:#fff;color:var(--text);padding:10px 12px;border-radius:10px;min-width:68px}
    .btn.primary{background:var(--primary);color:#fff;border-color:transparent}
    .btn.primary:hover{filter:brightness(1.05)}
    .btn:disabled{opacity:.6;cursor:not-allowed}
    .actions{display:flex;gap:10px;margin-top:10px}
    .pill{display:inline-flex;align-items:center;gap:8px;padding:2px 8px;border-radius:999px;background:#eaf1ff;color:#1d4ed8;font-weight:600}
    .diagram{height:260px;display:flex;align-items:center;justify-content:center}
    .circle-outer{border:4px solid #93c5fd;background:#eff6ff;border-radius:9999px;display:flex;align-items:center;justify-content:center;transition:width .2s,height .2s}
    .circle-inner{background:#fff;border:2px solid #bfdbfe;border-radius:9999px;transition:width .2s,height .2s}
    .stats{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px}
    .stat label{display:block;font-size:12px;color:var(--muted)}
    .stat div{font-weight:600}
    .note{color:var(--muted);font-size:14px}
    .list{margin:8px 0 0 18px}
    .error{color:var(--danger);font-size:13px;margin-top:6px}
    .muted{color:var(--muted)}
    .kbd{font:12px/1.2 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;background:#f3f4f6;border:1px solid #e5e7eb;border-bottom-width:2px;padding:1px 5px;border-radius:6px}
  </style>
  <meta name="description" content="卷材厚度/内径/外径/长度互算：输入任意三个求第四个。" />
  <meta name="color-scheme" content="light dark" />
  <link rel="icon" href="data:," />
  <script>
    // 工具：获取数值或 null（空字符串/NaN 视为 null）
    function valOf(id){
      const v = document.getElementById(id).value.trim();
      if(v==='') return null;
      const n = Number(v);
      return Number.isFinite(n) ? n : null;
    }

    // 计算函数（单位换算：输入厚度/直径 mm，长度 m；内部以米计算）
    function calcLength(mmT, mmd, mmD){
      const t = mmT/1000, d = mmd/1000, D = mmD/1000; // m
      if(t<=0||D<=0||d<0||D<=d) return null;
      return Math.PI * (D*D - d*d) / (4*t); // m
    }
    function calcThickness(lengthM, mmd, mmD){
      const d = mmd/1000, D = mmD/1000, L = lengthM; // m
      if(L<=0||D<=0||d<0||D<=d) return null;
      const t = Math.PI * (D*D - d*d) / (4*L); // m
      return t*1000; // mm
    }
    function calcInner(lengthM, mmT, mmD){
      const t = mmT/1000, D = mmD/1000, L = lengthM; // m
      if(L<=0||t<=0||D<=0) return null;
      const rad = D*D - (4*L*t)/Math.PI;
      if(rad < 0) return null;
      return Math.sqrt(rad)*1000; // mm
    }
    function calcOuter(lengthM, mmT, mmD){
      const t = mmT/1000, d = mmD/1000, L = lengthM; // m
      if(L<=0||t<=0||d<0) return null;
      const rad = (4*L*t)/Math.PI + d*d;
      if(rad < 0) return null;
      return Math.sqrt(rad)*1000; // mm
    }

    function round(n, dp){
      const f = Math.pow(10, dp|0); return Math.round(n*f)/f;
    }

    function updateDiagram(){
      const inner = valOf('inner');
      const outer = valOf('outer');
      const o = document.getElementById('circle-outer');
      const i = document.getElementById('circle-inner');
      const clamp = v => Math.max(10, Math.min(220, v));
      const ow = outer? clamp(outer/20) : 60;
      const iw = inner? clamp(inner/20) : 20;
      o.style.width = ow+'px';
      o.style.height = ow+'px';
      i.style.width = iw+'px';
      i.style.height = iw+'px';
      document.getElementById('stat-t').textContent = valOf('thick')!=null? (valOf('thick')+' mm'):'待计算';
      document.getElementById('stat-i').textContent = inner!=null? (inner+' mm'):'待计算';
      document.getElementById('stat-o').textContent = outer!=null? (outer+' mm'):'待计算';
      document.getElementById('stat-l').textContent = valOf('len')!=null? (valOf('len')+' m'):'待计算';
    }

    function countFilled(){
      const vals = [valOf('thick'), valOf('inner'), valOf('outer'), valOf('len')];
      return vals.filter(v => v!=null && v>0).length;
    }

    function setError(msg){
      document.getElementById('error').textContent = msg || '';
    }

    function disablePerField(){
      const t = valOf('thick'), i = valOf('inner'), o = valOf('outer'), l = valOf('len');
      document.getElementById('btn-t').disabled = !(i&&o&&l);
      document.getElementById('btn-i').disabled = !(t&&o&&l);
      document.getElementById('btn-o').disabled = !(t&&i&&l);
      document.getElementById('btn-l').disabled = !(t&&i&&o);
      document.getElementById('btn-auto').disabled = countFilled()!==3;
    }

    function onAnyInput(){
      updateDiagram();
      disablePerField();
      setError('');
    }

    function calcOne(which){
      setError('');
      const t = valOf('thick'), i = valOf('inner'), o = valOf('outer'), l = valOf('len');
      let res=null;
      if(which==='t') res = calcThickness(l,i,o);
      if(which==='i') res = calcInner(l,t,o);
      if(which==='o') res = calcOuter(l,t,i);
      if(which==='l') res = calcLength(t,i,o);
      if(res==null || !Number.isFinite(res)){
        setError('参数组合无效，无法计算。请检查是否为正数，且外径 > 内径。');
        return;
      }
      if(which==='t') document.getElementById('thick').value = round(res,3);
      if(which==='i') document.getElementById('inner').value = round(res,1);
      if(which==='o') document.getElementById('outer').value = round(res,1);
      if(which==='l') document.getElementById('len').value   = round(res,2);
      onAnyInput();
    }

    function calcAuto(){
      const t = valOf('thick'), i = valOf('inner'), o = valOf('outer'), l = valOf('len');
      if(t==null) return calcOne('t');
      if(i==null) return calcOne('i');
      if(o==null) return calcOne('o');
      if(l==null) return calcOne('l');
    }

    function resetAll(){
      document.getElementById('thick').value = 0.2;
      document.getElementById('inner').value = 508;
      document.getElementById('outer').value = 1000;
      document.getElementById('len').value   = '';
      onAnyInput();
    }

    window.addEventListener('DOMContentLoaded', () => {
      for(const id of ['thick','inner','outer','len']){
        document.getElementById(id).addEventListener('input', onAnyInput);
        document.getElementById(id).addEventListener('blur', onAnyInput);
      }
      document.getElementById('btn-t').addEventListener('click', ()=>calcOne('t'));
      document.getElementById('btn-i').addEventListener('click', ()=>calcOne('i'));
      document.getElementById('btn-o').addEventListener('click', ()=>calcOne('o'));
      document.getElementById('btn-l').addEventListener('click', ()=>calcOne('l'));
      document.getElementById('btn-auto').addEventListener('click', calcAuto);
      document.getElementById('btn-reset').addEventListener('click', resetAll);
      resetAll();
    });
  </script>
  <!-- 简单图标 -->
  <svg xmlns="http://www.w3.org/2000/svg" style="display:none">
    <symbol id="ico-calc" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <rect x="4" y="2" width="16" height="20" rx="2"/><line x1="8" y1="6" x2="16" y2="6"/>
      <line x1="16" y1="14" x2="16" y2="18"/><path d="M8 14h.01M12 14h.01M8 18h.01M12 18h.01"/>
    </symbol>
    <symbol id="ico-ruler" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <path d="M3 8l13 13a2 2 0 0 0 2.83 0l1.34-1.34a2 2 0 0 0 0-2.83L7.17 3 3 7.17z"/>
      <path d="M14 7l3 3M11 10l3 3M8 13l3 3"/>
    </symbol>
  </svg>
</head>
<body>
  <div class="container">
    <h1><span class="pill"><svg width="16" height="16"><use href="#ico-calc"/></svg> 卷材计算器</span></h1>

    <div class="grid">
      <div class="card">
        <div class="card-h"><svg width="16" height="16" style="vertical-align:-2px"><use href="#ico-ruler"/></svg> 卷材参数</div>
        <div class="card-b">
          <div class="row">
            <div class="field">
              <label for="thick">厚度 (mm)</label>
              <div class="input-wrap">
                <input id="thick" type="number" step="0.001" min="0.001" placeholder="留空则计算厚度" />
                <button id="btn-t" class="btn">计算</button>
              </div>
            </div>

            <div class="field">
              <label for="inner">内径 (mm)</label>
              <div class="input-wrap">
                <input id="inner" type="number" step="0.1" min="0.1" placeholder="留空则计算内径" />
                <button id="btn-i" class="btn">计算</button>
              </div>
            </div>

            <div class="field">
              <label for="outer">外径 (mm)</label>
              <div class="input-wrap">
                <input id="outer" type="number" step="0.1" min="0.1" placeholder="留空则计算外径" />
                <button id="btn-o" class="btn">计算</button>
              </div>
            </div>

            <div class="field">
              <label for="len">长度 (m)</label>
              <div class="input-wrap">
                <input id="len" type="number" step="0.01" min="0.01" placeholder="留空则计算长度" />
                <button id="btn-l" class="btn">计算</button>
              </div>
            </div>
          </div>

          <div class="actions">
            <button id="btn-auto" class="btn primary">自动计算缺失参数</button>
            <button id="btn-reset" class="btn">重置</button>
          </div>
          <div id="error" class="error"></div>
        </div>
      </div>

      <div class="card">
        <div class="card-h">卷材示意图</div>
        <div class="card-b">
          <div class="diagram">
            <div id="circle-outer" class="circle-outer" style="width:100px;height:100px">
              <div id="circle-inner" class="circle-inner" style="width:40px;height:40px"></div>
            </div>
          </div>
          <div class="stats">
            <div class="stat"><label>厚度</label><div id="stat-t" class="value muted">待计算</div></div>
            <div class="stat"><label>内径</label><div id="stat-i" class="value muted">待计算</div></div>
            <div class="stat"><label>外径</label><div id="stat-o" class="value muted">待计算</div></div>
            <div class="stat"><label>长度</label><div id="stat-l" class="value muted">待计算</div></div>
          </div>
        </div>
      </div>
    </div>

    <div class="card" style="margin-top:16px">
      <div class="card-h">计算说明</div>
      <div class="card-b">
        <div class="note">
          <div><strong>计算公式</strong></div>
          <div>长度 L(m) = π × (外径² − 内径²) ÷ (4 × 厚度)</div>
          <div class="list">
            <div>外径/内径/厚度以 mm 输入，内部自动换算到米计算。</div>
          </div>
          <div style="margin-top:8px"><strong>由此推导</strong></div>
          <div class="list">
            <div>外径 D = √( 内径² + 4 L t / π )</div>
            <div>内径 d = √( 外径² − 4 L t / π )</div>
            <div>厚度 t = π(外径² − 内径²) / (4 L)</div>
          </div>
          <div style="margin-top:8px"><strong>使用说明</strong></div>
          <div class="list">
            <div>1) 输入任意三个已知参数，留空一个待求参数。</div>
            <div>2) 点击对应“计算”或“自动计算缺失参数”。</div>
            <div>3) 不合理组合（如 外径 ≤ 内径）会给出提示。</div>
          </div>
          <div style="margin-top:8px"><strong>默认参数</strong></div>
          <div class="list">
            <div>厚度 0.2 mm</div>
            <div>内径 508 mm（标准卷芯）</div>
            <div>外径 1000 mm</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
</html>

